// Copyright (c) 2019 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import Foundation

/// Parses Swift Function times generated by `swiftc`
/// if you pass the flags `-Xfrontend -debug-time-function-bodies`
class SwiftCompilerFunctionTimeOptionParser: SwiftCompilerTimeOptionParser {

    private static let compilerFlag = "-debug-time-function-bodies"

    func hasCompilerFlag(commandDesc: String) -> Bool {
        commandDesc.range(of: Self.compilerFlag) != nil
    }

    func parse(from commands: [String: Int]) -> [String: [SwiftFunctionTime]] {
        let functionsPerFile = commands.compactMap { parse(command: $0.key, occurrences: $0.value) }
            .joined().reduce([:]) { (functionsPerFile, functionTime)
        -> [String: [SwiftFunctionTime]] in
            var functionsPerFile = functionsPerFile
            if var functions = functionsPerFile[functionTime.file] {
                functions.append(functionTime)
                functionsPerFile[functionTime.file] = functions
            } else {
                functionsPerFile[functionTime.file] = [functionTime]
            }
            return functionsPerFile
        }
        return functionsPerFile
    }

    private func parse(command: String, occurrences: Int) -> [SwiftFunctionTime]? {
        let functions: [SwiftFunctionTime] = command.components(separatedBy: "\r").compactMap { commandLine in

            // 0.14ms   /users/mnf/project/SomeFile.swift:10:12   someMethod(param:)
            let parts = commandLine.components(separatedBy: "\t")

            guard parts.count == 3 else {
                return nil
            }

            // 0.14ms
            let duration = parseCompileDuration(parts[0])

            // /users/mnf/project/SomeFile.swift:10:12
            let fileAndLocation = parts[1]
            guard let (file, line, column) = parseNameAndLocation(from: fileAndLocation) else {
                return nil
            }

            // someMethod(param:)
            let signature = parts[2]

            return SwiftFunctionTime(file: file,
                                     durationMS: duration,
                                     startingLine: line,
                                     startingColumn: column,
                                     signature: signature,
                                     occurrences: occurrences)
        }

        return functions
    }
}
